#include <linux/spinlock.h>
#include <linux/preempt.h>

#define __lockfunc __section(".spinlock.text")

void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name,
                          struct lock_class_key *key, short inner)
{
    raw_spinlock_t l = {};

    *lock = l;
}

#ifdef CONFIG_SMP
void do_raw_spin_lock(raw_spinlock_t *lock)
{
    arch_spin_lock(&lock->raw_lock);
}

int do_raw_spin_trylock(raw_spinlock_t *lock)
{
    int ret = arch_spin_trylock(&lock->raw_lock);

    return ret;
}

void do_raw_spin_unlock(raw_spinlock_t *lock)
{
    arch_spin_unlock(&lock->raw_lock);
}

static inline void __raw_spin_lock_irq(raw_spinlock_t *lock)
{
    local_irq_disable();
    preempt_disable();
}

void __lockfunc _raw_spin_lock_irq(raw_spinlock_t *lock)
{
    __raw_spin_lock_irq(lock);
}

unsigned long __lockfunc _raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);
    preempt_disable();

    return flags;
}

void __lockfunc _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags)
{
    arch_spin_unlock(&lock->raw_lock);
    local_irq_restore(flags);
    preempt_enable();
}

void __lockfunc _raw_spin_unlock_irq(raw_spinlock_t *lock)
{
    arch_spin_unlock(&lock->raw_lock);
    local_irq_enable();
    preempt_enable();
}

void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{
    preempt_disable();
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock)
{
    do_raw_spin_unlock(lock);
    preempt_enable();
}

int __lockfunc _raw_spin_trylock(raw_spinlock_t *lock)
{
    preempt_disable();
    if (do_raw_spin_trylock(lock))
    {
        return 1;
    }
    preempt_enable();

    return 0;
}
#else
void _raw_spin_lock(raw_spinlock_t *lock)
{
    (void)lock;
    preempt_disable();
}

void _raw_spin_unlock(raw_spinlock_t *lock)
{
    (void)lock;
    preempt_enable();
}

unsigned long _raw_spin_lock_irqsave(raw_spinlock_t *lock)
{
    unsigned long flags;

    local_irq_save(flags);

    return flags;
}

void _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags)
{
    (void)lock;
    local_irq_restore(flags);
}

void _raw_spin_lock_irq(raw_spinlock_t *lock)
{
    (void)lock;
    local_irq_disable();
    preempt_disable();
}

void _raw_spin_unlock_irq(raw_spinlock_t *lock)
{
    (void)lock;
    local_irq_enable();
    preempt_enable();
}

int _raw_spin_trylock(raw_spinlock_t *lock)
{
    preempt_disable();

    return 1;
}

#endif
